iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0

D04 - 設計資料模型我們有提到過領域驅動開發以及資料模型設計。在設計的時候我們處於一個理想化的世界,不必太在乎具體怎麼實作,只要把使用者需求映射成資料模型與工作流程就可以了,所以一開始設計的時候通常只會考慮到綠色區塊,可是很快我們就會發現執行上的困難點。

https://ithelp.ithome.com.tw/upload/images/20231010/201586153f78kf5CEp.png

資料傳輸其實是有格式限制的,它無法直接把每個執行環境的型別轉換為可序列化的二元碼。舉例來說 literal typeJSON 裡面就是 stringfunction 無法被序列化,如果我們直接把 BigInt 或是 recursive object 放入 JSON.stringify 更是會直接報錯。

該如何解決呢? 其實就是要自己做轉換啦 ! 類似這樣的模式其實非常常見,我們可以把它做歸納,負責執行這類任務的模型就叫做資料傳輸模型 (Data Transfer Object, DTO)。它會介於領域模型與外部IO之間,它雖然無法充分表示與需求相關的模型,卻可以直接序列化後進行傳輸。

傳輸模型與領域模型的轉換

接下來我們就以 UserUserDocument 為範例來說明如何做領域模型到傳輸模型之間的轉換。

我喜歡把轉換的邏輯寫在傳輸模型中,這是參考 Uncle Bobclear architecture 的概念,內部核心商業邏輯不應該依賴外部模組,所以 User 不應該包含如何轉換成 UserDocument 的邏輯。
https://ithelp.ithome.com.tw/upload/images/20231010/201586153DyvKYKdaB.png
來源

從領域模型到傳輸模型很簡單可以直接轉。

const mongooseSchema: mongoose.Schema = new mongoose.Schema<UserDocument>({
  role: String,
  name: String,
})

const of =
  (name: string) =>
  (role: string): UserDocument => ({
    role,
    name,
  })

const fromUser = (user: User) =>
  pipe(
    M.value(user._tag),
    // 相當於 (user._tag)=>of(user.name)(user._tag)
    M.when('Administrator', of(user.name)),
    M.when('Participant', of(user.name)),
    M.exhaustive
  )

https://ithelp.ithome.com.tw/upload/images/20231010/20158615Lm0wel3d9x.png

不過從傳輸模型轉回領域模型就可能出錯了,這是因為 UserDocument.role 的型別是 string ,它有可能轉不回 User._tag: Administrator | Participant,所以我們要做錯誤處理,像是以下這樣

const onToUserError = () =>
  Either.left(
    TransformError.of({
      from: 'UserDocument',
      to: 'User',
      message: 'role should be Administrator or Participant',
    })
  )

const toUser = (doc: UserDocument): Either.Either<TransformError, User> =>
  pipe(
    M.value(doc.role),
    M.when('Administrator', () => Either.right(Administrator.of(doc.name))),
    M.when('Participant', () => Either.right(Participant.of(doc.name))),
    M.orElse(onToUserError)
  )

今天有講到 Clean Archtecture,其中方便抽換外部模組 大概算是這個架構的特長了,可惜的是我們大部分看到的 Clean Archtecture 的實作範例都是基於 Class 的,而且常常需要撰寫很多實際上用不到的抽象類別。

接下來兩天會跟大家分享如何基於 FP 達到同樣的目標。


上一篇
D24 - 實作異步流程 (十)
下一篇
D26 - 更多依賴注入
系列文
從 Next.js 開始的 Functional Programming30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言